package com.wish233.proxy;

import cn.hutool.core.collection.CollectionUtil;
import com.wish233.application.RpcApplication;
import com.wish233.config.RegistryConfig;
import com.wish233.config.RpcConfig;
import com.wish233.constant.RpcConstant;
import com.wish233.loadbalance.LoadBalancer;
import com.wish233.loadbalance.factory.LoadBalancerFactory;
import com.wish233.model.register.ServiceMetaInfo;
import com.wish233.model.rpc.RpcRequest;
import com.wish233.model.rpc.RpcResponse;
import com.wish233.register.Registry;
import com.wish233.register.factory.RegistryFactory;
import com.wish233.retry.RetryStrategy;
import com.wish233.retry.RetryStrategyFactory;
import com.wish233.tolerant.TolerantStrategy;
import com.wish233.tolerant.TolerantStrategyFactory;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 服务代理（jdk动态代理）
 * TCP协议
 *
 * @author WHH
 */
@Slf4j
public class NetServiceProxy implements InvocationHandler {

    private final RpcConfig rpcConfig = RpcApplication.getRpcConfig();


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //构造请求体
        RpcRequest rpcRequest = new RpcRequest();
        rpcRequest.setServiceName(method.getDeclaringClass().getName());
        rpcRequest.setMethodName(method.getName());
        rpcRequest.setParameterTypes(method.getParameterTypes());
        rpcRequest.setArgs(args);
        //序列化发请求
        //从注册中心获取请求地址
        try {
            RegistryConfig registryConfig = rpcConfig.getRegistryConfig();
            Registry registry = RegistryFactory.getInstance(registryConfig.getRegistry());
            ServiceMetaInfo serviceMetaInfo = new ServiceMetaInfo();
            serviceMetaInfo.setServiceName(rpcRequest.getServiceName());
            serviceMetaInfo.setServiceVersion(RpcConstant.DEFAULT_SERVICE_VERSION);
            List<ServiceMetaInfo> serviceMetaInfos = registry.serviceDiscovery(serviceMetaInfo.getServiceKey());
            if (CollectionUtil.isEmpty(serviceMetaInfos)) {
                throw new RuntimeException("暂无服务");
            }
            //负载均衡器
            LoadBalancer loadBalancer = LoadBalancerFactory.getInstance(rpcConfig.getLoadBalancer());
            Map<String, Object> requestParams = new HashMap<>();
            requestParams.put("method", rpcRequest.getMethodName());
            //负载均衡
            ServiceMetaInfo selectedService = loadBalancer.select(serviceMetaInfos, requestParams);
            RetryStrategy retryStrategy = RetryStrategyFactory.getInstance(rpcConfig.getRetryStrategy());
            RpcResponse response;
            try {
                 response = retryStrategy.retry(() ->
                        NetClientHandler.doRequest(rpcRequest, selectedService)
                );
            } catch (Exception e) {
                //获取容错策略
                TolerantStrategy tolerantStrategy = TolerantStrategyFactory.getInstance(rpcConfig.getTolerantStrategy());
                Map<String, Object> context = new HashMap<>();
                context.put("returnType", method.getReturnType());
                context.put("serviceMetaInfos", serviceMetaInfos);
                context.put("rpcRequest", rpcRequest);
                response = tolerantStrategy.doTolerant(context, e);
            }
            return response.getData();
        } catch (Exception e) {
            throw new RuntimeException("调用失败！", e);
        }

    }
}
